<template>
  <ElCard>
    <template #header>
      <div class="card-header">
        <span>界面设计</span>
        <div>
          <ElButton class="button" text @click="push('/lowcode/list')">返回</ElButton>
          <ElButton class="button" text @click="handleViewDesign">预览</ElButton>
          <ElButton class="button" text @click="showViewDialog">查看配置</ElButton>
          <ElButton class="button" text @click="showImportDialog">导入配置</ElButton>
          <ElButton class="button" type="primary" :loading="saveLoading" @click="handleSaveDesign">保存</ElButton>
        </div>
      </div>
    </template>
    <ElRow height="200px">
      <ElCol :span="24">
        <ElForm :model="pageData" label-width="100px" :inline="true">
          <ElFormItem label="名称" prop="name" :required="true">
            <ElInput style="width: 220px" v-model="pageData.name" :clearable="true" />
          </ElFormItem>
          <ElFormItem label="标题" prop="title" :required="true">
            <ElInput style="width: 220px" v-model="pageData.title" :clearable="true" />
          </ElFormItem>
          <ElFormItem label="子标题" prop="caption">
            <ElInput style="width: 220px" v-model="pageData.caption" :clearable="true" />
          </ElFormItem>
          <ElFormItem label="打开方式" prop="target" :required="true">
            <ElSelect style="width: 220px" v-model="pageData.target" :clearable="true">
              <ElOption label="新标签页" value="blank" />
              <ElOption label="对话框" value="dialog" />
            </ElSelect>
          </ElFormItem>
          <ElFormItem label="布局风格" prop="layout" :required="true">
            <ElSelect style="width: 220px" v-model="pageData.layout" :clearable="true">
              <ElOption label="默认单表" value="simple-default" />
              <ElOption label="主子表" value="multi-table-default" />
            </ElSelect>
          </ElFormItem>
          <ElFormItem label="列表接口" prop="getListApi" :required="true">
            <ElInput style="width: 220px" v-model="pageData.getListApi" :clearable="true" />
          </ElFormItem>
          <ElFormItem label="新增接口" prop="addApi">
            <ElInput style="width: 220px" v-model="pageData.addApi" :clearable="true" />
          </ElFormItem>
          <ElFormItem label="编辑接口" prop="editApi">
            <ElInput style="width: 220px" v-model="pageData.editApi" :clearable="true" />
          </ElFormItem>
          <ElFormItem label="删除接口" prop="delApi">
            <ElInput style="width: 220px" v-model="pageData.delApi" :clearable="true" />
          </ElFormItem>
          <ElFormItem label="详情接口" prop="detailApi">
            <ElInput style="width: 220px" v-model="pageData.detailApi" :clearable="true" />
          </ElFormItem>
        </ElForm>
      </ElCol>
    </ElRow>
    <ElRow>
      <ElCol :span="18">
        <ElTable :data="pageData?.schemas" border style="width: 100%" @cell-click="handleShowProps">
          <ElTableColumn label="字段" prop="field" align="left" />
          <ElTableColumn label="名称" prop="label" align="left" />
          <ElTableColumn label="列表显示" prop="table" align="center" width="90">
            <template #default="scope">
              <ElCheckbox v-model="scope.row.table.show" @change="handleShowStateChanged(scope.row, scope.column, scope.row.table.show)" />
            </template>
          </ElTableColumn>
          <ElTableColumn label="查询显示" prop="search" align="center" width="90">
            <template #default="scope">
              <ElCheckbox v-model="scope.row.search.show" :disabled="scope.row.type === 'index' || scope.row.type === 'selection'" @change="handleShowStateChanged(scope.row, scope.column, scope.row.table.show)" />
            </template>
          </ElTableColumn>
          <ElTableColumn label="表单显示" prop="form" align="center" width="90">
            <template #default="scope">
              <ElCheckbox v-model="scope.row.form.show" :disabled="scope.row.type === 'index' || scope.row.type === 'selection'" @change="handleShowStateChanged(scope.row, scope.column, scope.row.table.show)" />
            </template>
          </ElTableColumn>
          <ElTableColumn label="详情显示" prop="detail" align="center" width="90">
            <template #default="scope">
              <ElCheckbox v-model="scope.row.detail.show" :disabled="scope.row.type === 'index' || scope.row.type === 'selection'" @change="handleShowStateChanged(scope.row, scope.column, scope.row.table.show)" />
            </template>
          </ElTableColumn>
          <ElTableColumn label="操作" prop="operator" align="center" width="150">
            <template #default="scope">
              <ElButton v-if="scope.$index > 0" text @click="handleMove(scope.$index, 'up')"><Icon icon="ant-design:arrow-up-outlined" /></ElButton>
              <ElButton v-if="scope.$index < pageData.schemas.length - 1" text @click="handleMove(scope.$index, 'down')"><Icon icon="ant-design:arrow-down-outlined" /></ElButton>
            </template>
          </ElTableColumn>
        </ElTable>
      </ElCol>
      <ElCol :span="6">
        <PropertyGrid v-model="propsData" :columnProperty="columnProperty" />
      </ElCol>
    </ElRow>

    <Dialog v-model="dialogVisible" :title="dialogTitle" :maxHeight="300">
      <JsonEditor v-if="dialogType == 0" v-model="pageData" />
      <ElInput :rows="12" v-if="dialogType == 1" v-model="pageDataJson" type="textarea" />
      <p style="color: #dd1919">{{ errMessage }}</p>
      <template #footer>
        <ElButton v-if="dialogType == 1" @click="handleImport">{{ '导入' }}</ElButton>
        <ElButton @click="dialogVisible = false">{{ '关闭' }}</ElButton>
      </template>
    </Dialog>
  </ElCard>
</template>

<script lang="tsx" setup>
import { ElCard, ElRow, ElCol, ElButton, ElTable, ElTableColumn, ElForm, ElFormItem, ElCheckbox, ElSelect, ElOption, ElInput, ElMessage } from 'element-plus'
import { Icon } from '@/components/Icon'
import { computed, onMounted, ref } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { Dialog } from '@/components/Dialog'
import { JsonEditor } from '@/components/JsonEditor'
import { getLowcodeApi, saveLowcodeApi } from '@/api/lowcode'
import { FieldProperties, LowcodeEntity, PageDataProperty } from '@/components/Lowcode/src/types/Lowcode'
import PropertyGrid from '@/components/Lowcode/src/components/PropertyGrid.vue'
import { isEmptyVal, isObject } from '@/utils/is'
import { CrudSchema } from '@/hooks/web/useCrudSchemas'

const { push } = useRouter()

const pageData = ref<PageDataProperty>({
  title: '',
  caption: '',
  target: '',
  layout: '',
  getListApi: '',
  delApi: '',
  addApi: '',
  editApi: '',
  detailApi: '',
  schemas: []
})
const currentProp = ref<FieldProperties>()
const rowIndex = ref(-1)
const columnProperty = ref('')
const currentCell = ref()
const pageDataJson = ref('')
const changed = ref(false)
const errMessage = ref('')
const saveLoading = ref(false)
const allowClickFields = ['table', 'form', 'detail', 'search']

const handleShowProps = (row, column, cell) => {
  if (row.type === 'selection' || row.type === 'index') {
    return
  }
  if (allowClickFields.indexOf(column.property) === -1) {
    return
  }
  let index = pageData.value?.schemas.indexOf(row)
  if (column.property === columnProperty.value && index === rowIndex.value) {
    return
  }
  if (cell && typeof cell != 'boolean') {
    if (currentCell.value) {
      currentCell.value.style['background-color'] = ''
    }
    if (cell.style) {
      cell.style['background-color'] = 'rgba(59, 130, 246, 0.5)'
    }
    currentCell.value = cell
  }
  // 获取单元格属性、行索引等信息
  columnProperty.value = column.property
  rowIndex.value = index
  currentProp.value = row[column.property]
}

const handleShowStateChanged = (row, column, cellValue: '') => {
  if (allowClickFields.indexOf(column.property) === -1) {
    return
  }
  handleShowProps(row, column, cellValue)
}

const handleMove = (index, oper) => {
  let exchangeRow
  let currentRow = pageData.value.schemas[index]
  switch (oper) {
    case 'up':
      if (index == 0) {
        break
      }
      exchangeRow = pageData.value.schemas[index - 1]
      pageData.value.schemas[index - 1] = currentRow
      pageData.value.schemas[index] = exchangeRow
      break
    case 'down':
      if (index == pageData.value.schemas.length - 1) {
        break
      }
      exchangeRow = pageData.value.schemas[index + 1]
      pageData.value.schemas[index + 1] = currentRow
      pageData.value.schemas[index] = exchangeRow
      break
    default:
      break
  }
}

const dialogVisible = ref(false)
const dialogTitle = ref('')
const dialogType = ref(-1)

const showViewDialog = () => {
  dialogTitle.value = '查看JSON'
  dialogVisible.value = true
  dialogType.value = 0
}

const showImportDialog = () => {
  dialogTitle.value = '导入配置'
  dialogVisible.value = true
  dialogType.value = 1
  let data = JSON.parse(JSON.stringify(pageData.value))
  resovePageData(data)
  pageDataJson.value = JSON.stringify(data, null, 4)
}

const propsData = computed({
  get() {
    if (!columnProperty.value && rowIndex.value === -1) {
      return {}
    }
    return pageData.value.schemas[rowIndex.value][columnProperty.value]
  },
  set(newVal) {
    pageData.value.schemas[rowIndex.value][columnProperty.value] = newVal
  }
})

// const syntaxHighlight = (json: any) => {
//   if (typeof json != 'string') {
//     json = JSON.stringify(json, undefined, 2)
//   }
//   json = json.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>')
//   return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) {
//     let cls = 'color:#D19A66'
//     if (/^"/.test(match)) {
//       if (/:$/.test(match)) {
//         cls = 'color:#F92A0F'
//       } else {
//         cls = 'color:#44C91B'
//       }
//     } else if (/true|false/.test(match)) {
//       cls = 'color:#1B73C9'
//     } else if (/null/.test(match)) {
//       cls = 'color:#C586C0'
//     }
//     return `<span style=${cls}>${match}</span>`
//   })
// }

const handleViewDesign = () => {
  if (!pageData.value.id) {
    console.error('cannot preview before saved')
    return
  }
  push('/lowcode/example-page/' + pageData.value.id)
}

const handleImport = () => {
  errMessage.value = ''
  // 更新pageData值
  let parseData
  try {
    parseData = JSON.parse(pageDataJson.value)
    recoveryPageData(parseData)
    pageData.value = parseData
  } catch (e) {
    errMessage.value = (e as Error).message
  }
  if (parseData.id && parseData.id !== pageData.value.id) {
    throw new Error('error: id does not match')
  }
  errMessage.value = ''
  dialogVisible.value = false
}

let delFieldNamesForTableSchema: string[] = []
let delFieldNamesForSearchSchema: string[] = []
let delFieldNamesForFormSchema: string[] = []
let delFieldNamesForDetailSchema: string[] = []
const resovePageData = (data) => {
  if (!data || !data.schemas || data.schemas.length === 0) {
    return
  }
  data.schemas.forEach((schema: CrudSchema) => {
    resolveMultiLevelProps(schema.table || {}, delFieldNamesForTableSchema)
    resolveMultiLevelProps(schema.search || {}, delFieldNamesForSearchSchema)
    resolveMultiLevelProps(schema.form || {}, delFieldNamesForFormSchema)
    resolveMultiLevelProps(schema.detail || {}, delFieldNamesForDetailSchema)
    if (schema.children) {
      resovePageData(schema.children)
    }
  })
}

const recoveryPageData = (data) => {
  if (!data || !data.schemas || data.schemas.length === 0) {
    return
  }
  data.schemas.forEach((schema: CrudSchema) => {
    recoveryMultiLevelProps(schema.table || {})
    recoveryMultiLevelProps(schema.search || {})
    recoveryMultiLevelProps(schema.form || {})
    recoveryMultiLevelProps(schema.detail || {})
    if (schema.children) {
      recoveryPageData(schema.children)
    }
  })
  pageData.value = data
}

/**
 *定义需要特殊处理转为对象的属性
 */
const specialPropertyIfHasValueToObject = ['componentProps.options']
const specialPropertyIfHasValueToFunction = ['slots.default']

/**
 * 解析表单数据以标准格式存储
 *
 * @param data
 */
const resolveMultiLevelProps = (data: any, delFieldNames: string[]) => {
  // let delFieldNames: string[] = ['label', 'field', 'show', 'dataSource', 'options', 'span', 'xs', 'sm', 'md', 'lg', 'xl', 'tag', 'style', 'required', 'disabled', 'readonly', 'componentProps.required']
  // 显示属性转换适配表单属性
  data.hidden = !data.show
  if (!data.component) {
    data.component = 'Input'
  }
  for (let fieldName in data) {
    if (fieldName.indexOf('.') === -1) {
      continue
    }
    delFieldNames.push(fieldName)
    if (isEmptyVal(data[fieldName])) {
      continue
    }
    resetMultiLevelValue(fieldName, data[fieldName], fieldName.split('.'), data, 0)
  }
  delFieldNames.forEach((delFieldName) => {
    delete data[delFieldName]
  })
}
const resetMultiLevelValue = (fieldName: string, value: any, fieldNames: string[], data: object, level: number) => {
  if (level < fieldNames.length - 1) {
    if (isEmptyVal(data[fieldNames[level]])) {
      data[fieldNames[level]] = {}
    }
    resetMultiLevelValue(fieldName, value, fieldNames, data[fieldNames[level]], level + 1)
  } else {
    if (specialPropertyIfHasValueToObject.indexOf(fieldName) > -1 && value) {
      // 特殊处理：转对象
      data[fieldNames[level]] = JSON.parse(value) as Array<Object>
      console.log(data[fieldNames[level]])
    } else if (specialPropertyIfHasValueToFunction.indexOf(fieldName) > -1 && value) {
      data[fieldNames[level]] = value
    } else {
      data[fieldNames[level]] = value
    }
    // if (fieldName === 'componentProps.options' && value) {
    //   // 特殊处理
    //   data[fieldNames[level]] = JSON.parse(value)
    // } else {
    //   data[fieldNames[level]] = value
    // }
  }
}
/**
 * 将标准格式转换为配置表单可识别的格式
 * @param data
 */
const recoveryMultiLevelProps = (data: any) => {
  let delFieldNames: string[] = ['label', 'field', 'hidden', 'slots', 'formItemProps', 'componentProps', 'colProps']
  // 显示属性转换适配表单属性
  data.show = !data.hidden
  for (let fieldName in data) {
    if (!isObject(data[fieldName])) {
      continue
    }
    delFieldNames.push(fieldName)
    recoveryMultiLevelValue(fieldName, data[fieldName], data)
  }
  delFieldNames.forEach((delFieldName) => {
    delete data[delFieldName]
  })
}

const recoveryMultiLevelValue = (finalFieldName: string, subData: object, data: object) => {
  for (let fieldName in subData) {
    if (!isObject(subData[fieldName])) {
      if (specialPropertyIfHasValueToObject.indexOf(finalFieldName + '.' + fieldName) > -1 && subData[fieldName]) {
        // 特殊处理
        data[finalFieldName + '.' + fieldName] = JSON.stringify(subData[fieldName])
      } else if (specialPropertyIfHasValueToFunction.indexOf(finalFieldName + '.' + fieldName) > -1 && subData[fieldName]) {
        // 特殊处理
        data[finalFieldName + '.' + fieldName] = subData[fieldName]
      } else {
        data[finalFieldName + '.' + fieldName] = subData[fieldName]
      }
      // if (finalFieldName + '.' + fieldName === 'componentProps.options' && subData[fieldName]) {
      //   // 特殊处理
      //   data[finalFieldName + '.' + fieldName] = JSON.stringify(subData[fieldName])
      // } else {
      //   data[finalFieldName + '.' + fieldName] = subData[fieldName]
      // }
      continue
    }
    finalFieldName += '.' + fieldName
    recoveryMultiLevelValue(finalFieldName, subData[fieldName], data)
  }
}

const handleSaveDesign = () => {
  // 保存操作
  saveLoading.value = true
  // 数据清理 解决多层级属性问题
  let data = JSON.parse(JSON.stringify(pageData.value))
  resovePageData(data)
  let params: LowcodeEntity = {
    id: data.id || '',
    name: data.name || '',
    text: JSON.stringify(data)
  }
  saveLowcodeApi(params)
    .then((result) => {
      if (result) {
        changed.value = true
      }
      saveLoading.value = false
    })
    .catch((e) => {
      console.log(e)
      saveLoading.value = false
    })
}

onMounted(() => {
  let { params } = useRoute()
  let identifier: string = params.identifier as string
  if (!identifier) {
    return
  }
  getLowcodeApi(identifier).then((result) => {
    if (result && result.data) {
      try {
        let data = result.data.text ? JSON.parse(result.data.text) : {}
        recoveryPageData(data)
        Object.assign(pageData.value, { id: result.data.id, name: result.data.name })
      } catch (e: any) {
        console.error(e.message)
        ElMessage({
          showClose: true,
          message: 'Oops, this is a error message.',
          type: 'error',
          duration: 5000
        })
      }
    }
  })
})
</script>
<style>
.card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}
</style>
